package org.javahispano.javacup.tacticas.tacticas_aceptadas.CTeam.tactica;

import static org.javahispano.javacup.tacticas.tacticas_aceptadas.CTeam.jugador.IJugadorCT.Equipo.PROPIO;
import static org.javahispano.javacup.modelo.util.Constantes.centroArcoInf;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.javahispano.javacup.tacticas.tacticas_aceptadas.CTeam.jugador.IJugadorCT;
import org.javahispano.javacup.tacticas.tacticas_aceptadas.CTeam.util.Disparo;
import org.javahispano.javacup.tacticas.tacticas_aceptadas.CTeam.util.DistanciaMinima;
import org.javahispano.javacup.tacticas.tacticas_aceptadas.CTeam.util.Triangulation;
import org.javahispano.javacup.modelo.util.Constantes;
import org.javahispano.javacup.modelo.util.Posicion;
import org.javahispano.javacup.modelo.engine.SituacionPartido;

public class EstrategiaAtaqueCT implements IEstrategiaCT {
	private final SituacionPartido sp;

	private final ICTeam2011 tactica;

	private final Triangulation voronoiRivales;

	protected List<IJugadorCT> recuperacionActual;

	public EstrategiaAtaqueCT(SituacionPartido sp, ICTeam2011 tactica, Triangulation voronoiTodos,
			Triangulation voronoiRivales, Triangulation voronoiMios) {
		this.sp = sp;
		this.tactica = tactica;
		this.voronoiRivales = voronoiRivales;
	}

	@Override
	public boolean ejecutarIteracion() {
		double[] posB = sp.getTrayectoria(tactica.iteracionesRecuperacion());
		PosicionCT balon = new PosicionCT(posB[0], posB[1]);
		double aBalon = sp.balon().angulo(balon.getPos());

		int maxRecuperacion = 3;
		recuperacionActual = new ArrayList<IJugadorCT>();
		boolean controlBalon = false;
		double p[] = new double[] { 0.0, -0.25, 0.25 };
		int idx = 0;
		List<IJugadorCT> aRecuperar = new ArrayList<IJugadorCT>();
		for (IJugadorCT jug : tactica.previoJugadoresRecuperacion()) {
			if (tactica.jugadoresRecuperacion().contains(jug)) {
				aRecuperar.add(jug);
				if (aRecuperar.size() >= maxRecuperacion) {
					break;
				}
			}
		}

		for (IJugadorCT jug : tactica.jugadoresRecuperacion()) {
			if (jug.getIndice() == 0)
				continue;
			if (tactica.recuperando().size() > tactica.rivalesRecuperacion().size()) {
				break;
			}
			aRecuperar.add(jug);

			if (aRecuperar.size() >= maxRecuperacion) {
				break;
			}
		}

		for (IJugadorCT jug : aRecuperar) {
			controlBalon = controlBalon || jug.isControlBalon();
			tactica.recuperando().add(jug);
			jug.setSiguiente(balon.moverAngulo(aBalon, p[idx++ % p.length]));
			recuperacionActual.add(jug);
		}

		int[] excluir = new int[recuperacionActual.size() + 3];
		for (int i = 0; i < recuperacionActual.size(); i++) {
			excluir[i + 3] = recuperacionActual.get(i).getIndice();
		}
		excluir[0] = 0;
		excluir[1] = 1;
		excluir[2] = 2;

		// obtener Posiciones Posibles Pase
		int jugadoresRestantes = 8 - recuperacionActual.size();
		Map<IJugadorCT, PosicionCT> posPases = new LinkedHashMap<IJugadorCT, PosicionCT>();

		PosicionCT[] centros = voronoiRivales.centros().toArray(new PosicionCT[0]);
		int[] cercanos = balon.indicesMasCercanos(centros);
		int maxDifY = balon.getY() < 10 ? -5 : 0;
		for (int i = cercanos.length - 1; i >= 0; i--) {
			idx = cercanos[i];
			PosicionCT centro = centros[idx];
			Posicion c = centro.getPos();

			if (c.getY() < balon.getY() - maxDifY) {
				continue;
			}

			int indiceMioCercano = c.indiceMasCercano(sp.misJugadores(), excluir);
			double dMio = c.distancia(sp.misJugadores()[indiceMioCercano]);
			int indiceRivalCercano = c.indiceMasCercano(sp.rivales());
			double dRival = c.distancia(sp.rivales()[indiceRivalCercano]);

			if (dMio < dRival - Constantes.VELOCIDAD_MAX) {
				IJugadorCT jug = tactica.getJugadores(PROPIO).get(indiceMioCercano);
				posPases.put(jug, centro);
				int[] exNew = new int[excluir.length + 1];
				System.arraycopy(excluir, 0, exNew, 1, excluir.length);
				exNew[0] = indiceMioCercano;

				jug.setSiguiente(centro);

				jugadoresRestantes--;
			}

			if (jugadoresRestantes <= 0) {
				break;
			}
		}
		List<PosicionCT> posPasesFinal = new ArrayList<PosicionCT>(posPases.values());
		for (IJugadorCT j : posPases.keySet()) {
			posPasesFinal.add(j.getActual());
		}

		if (controlBalon) {
			PosicionCT ultimo = null;
			for (PosicionCT pos : posPasesFinal) {
				Disparo d = null;
				int[] itRemate = sp.iteracionesParaRematar();
				for (IJugadorCT jug : recuperacionActual) {
					d = jug.paseLibre(pos, itRemate[jug.getIndice()]);
					if (d == null) {
						break;
					} else {
						jug.disparar(pos, d);
					}
				}
				if (d != null) {
					ultimo = null;
					break;
				}
				ultimo = pos;
			}

			if (ultimo != null) {
				for (IJugadorCT jug : recuperacionActual) {
					jug.disparar(ultimo, new Disparo(45, 0.75));
				}
			}
		}

		// mantener un par de defensas
		List<PosicionCT> aDefender = new ArrayList<PosicionCT>();
		List<IJugadorCT> defensas = new ArrayList<IJugadorCT>();
		int[] rivCercanos = centroArcoInf.indicesMasCercanos(sp.rivales());
		for (int i = 0; i < 2; i++) {
			Posicion r = sp.rivales()[rivCercanos[i]];
			double a = r.angulo(centroArcoInf);
			IJugadorCT jugador = tactica.getJugadores(PROPIO).get(i + 1);
			if (!recuperacionActual.contains(jugador)) {
				aDefender.add((new PosicionCT(r).moverAngulo(a, 0.5)));
				defensas.add(jugador);
			}
		}

		DistanciaMinima dm = new DistanciaMinima(defensas, aDefender);
		defensas = dm.getOrdenados();
		for (int i = 0; i < defensas.size(); i++) {
			defensas.get(i).setSiguiente(aDefender.get(i));
		}

		return true;
	}

	protected PosicionCT posicionVoronoi(PosicionCT pos) {
		Map<PosicionCT, List<PosicionCT>> voronoi = voronoiRivales.voronoi();
		PosicionCT[] keys = voronoi.keySet().toArray(new PosicionCT[0]);
		int idx = pos.indiceMasCercano(keys);
		return keys[idx];
	}

}
